package com.tim.helper.analysis.xssd;

import com.tim.MainHelper;
import com.tim.util.StringAnalysisUtil;
import org.apache.commons.lang3.StringUtils;
import org.junit.Test;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 按代码、类路径，生成postman测试
 * @author Adminis
 *
 */
public class XssdService2Postman {

	@Test// 读取code字符串；按注解拆分为数组，分析数组，获取请求名、路径；拼接结果
	public void service2Postman() throws IOException{
		// 接口路径
		String code = "";
		String path = "E:\\gitlab\\exodus\\biz\\biz-pig\\biz-pig-api\\src\\main\\java\\com\\xqxc\\api\\pig\\biz\\account\\SmallTransportZoneService.java" +
				"";

		String GROUP_NAME = "transport";
		String HOST_NAME = "host";
		String TOKEN_NAME = "token";
		String TEST_SCRIPT = ReqGenerator.TEST_SCRIPT;

		String cmdPrefix = "cmdPrefix";
		// 获取cmd前缀、content
		List<String> classInfo = StringAnalysisUtil.getClassInfo(path, true);
		cmdPrefix = classInfo.get(0)+"."+classInfo.get(1);
		code = classInfo.get(2);

		List<String[]> reqArgs = getReqArgs(code, cmdPrefix, 0);

		if (reqArgs == null) return;
		ReqGenerator reqGenerator = new XssdReqGenerator();
		String reqItemContent = reqArgs.stream()
				.map(args->reqGenerator.getReq(
						args[0],
						GROUP_NAME,
						args[1],
						TOKEN_NAME,
						TEST_SCRIPT,
						HOST_NAME
				))
				.collect(Collectors.joining(","));
		String project = String.format(POSTMAN_COLLECTION_TEMPLATE, cmdPrefix, reqItemContent);
		Files.write(Paths.get(MainHelper.OUTPUT_DIR, cmdPrefix+".json"), project.getBytes(StandardCharsets.UTF_8));
		System.out.println(MainHelper.OUTPUT_DIR);
	}

	@Test// 读取code字符串；按注解拆分为数组，分析数组，获取请求名、路径；拼接结果
	public void multiPrint() throws IOException{
		// 接口文件路径、包路径
		String path = "E:\\gitlab\\exodus\\plat\\plat-pay\\plat-pay-api\\src\\main\\java\\com\\xqxc\\api\\plat\\pay\\AccountBindService.java" +
                "";
		File file = new File(path);
		if(!file.exists()){
			System.out.println("路径不存在！");
			return;
		}
		if(file.isDirectory() || true){
			Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>(){
				@Override
				public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)
						throws IOException
				{
					String pathStr = path.toString();
					if(pathStr.endsWith("java") && pathStr.contains("Service")){
//						System.out.println(pathStr);
						printOneService(pathStr);
					}
					return FileVisitResult.CONTINUE;
				}
			});
		}else{
			printOneService(path);
		}


	}

	@Test
    public void printClassComment() throws IOException {
        // 接口文件路径、包路径
        String path = "E:\\gitlab\\exodus\\plat\\plat-settle\\plat-settle-impl\\src\\main\\java\\com\\xqxc\\plat\\settle\\manager" +
				"";
		List<String> excludeDirList = Arrays.asList("bean".split(","));

		String[] excludeDirs = excludeDirList.stream()
				.filter(StringUtils::isNotBlank)
				.toArray(String[]::new);
        File file = new File(path);
        if(!file.exists()){
            System.out.println("路径不存在！");
            return;
        }
		Files.walkFileTree(Paths.get(path), new SimpleFileVisitor<Path>(){
			@Override
			public FileVisitResult preVisitDirectory(Path path, BasicFileAttributes attrs)
					throws IOException
			{
				String dirName = path.getFileName().toString();
				if(excludeDirs.length>0 && StringUtils.containsAny(dirName, excludeDirs)){
					return FileVisitResult.SKIP_SUBTREE;
				}
				return FileVisitResult.CONTINUE;
			}

			@Override
			public FileVisitResult visitFile(Path path, BasicFileAttributes attrs)
					throws IOException
			{
				String fileName = path.getFileName().toString();
				if(fileName.endsWith("java")){
//						System.out.println(pathStr);
					List<String> list = Files.readAllLines(path);
					String comment="";
					for (int i = 0; i < list.size(); i++) {
						String line = list.get(i);
						if(StringUtils.isBlank(line)){
							continue;
						}
						line = line.trim();
						if(StringUtils.startsWithAny(line, "import", "package")){
							// 跳过
							continue;
						}
						if(StringUtils.startsWithAny(line, "/*")){
							do{
								comment += StringAnalysisUtil.getComment(list.get(++i));
							}while (line.endsWith("*/"));
						}else if(line.startsWith("//")){
							comment = StringAnalysisUtil.getComment(line);
						}else if(Pattern.matches("^public\\s+((class)|(interface))[\\w\\W]+", line)){
							String className = line.split("\\s+")[2];
							System.out.println(className.split("\\{")[0]+"；"+comment);
							break;
						}
					}
				}
				return FileVisitResult.CONTINUE;
			}
		});
    }

	// reqName(无描述时取方法名), cmd(仅有方法名)
	private List<String[]> getReqArgs(String code, String cmdPrefix, int getCommon) {
		String[] strs = code.split("@CMD");
		if (strs.length < 2) {
			return getNoCmdReqArgs(code, getCommon);
		}
		List<String[]> reqArgs = new ArrayList<>();
		// 解析注解、方法签名中的请求名称、cmd信息；生成请求
		for (int i = 1; i < strs.length; i++) {
			String reqName = "", cmd = "";
			String[] lines = strs[i].split("[\r\n]+");
			String cmdAnnoLine = lines[0];
			// 优先从注解中获取reqName、cmd
			reqName = StringAnalysisUtil.getAnnoValue(cmdAnnoLine, "description");
			cmd = StringAnalysisUtil.getAnnoValue(cmdAnnoLine, "cmd");
			// reqName、cmd为空，从方法签名中获取对应值
			boolean needParse = StringUtils.isBlank(reqName) || StringUtils.isBlank(cmd);
			int j = 1;// 判定是否有普通方法
			String line="";
			for (; j < lines.length; j++) {
				line += lines[j];
				if (line.contains(")")) {// 方法签名行
					if(needParse){// 需要解析reqName、cmd
						String[] methodInfo = StringAnalysisUtil.getMethodInfo(line);
						reqName = StringUtils.isBlank(reqName) ? methodInfo[1] : reqName;
						cmd = StringUtils.isNotBlank(cmd) ? cmd : cmdPrefix + "." + methodInfo[1];
					}
					break;
				}
			}
			reqArgs.add(new String[]{reqName, cmd});

			if(j<lines.length-1){
				String subCode = Arrays.stream(lines)
						.skip(j+1)// 跳过j+1行
						.collect(Collectors.joining("\n"));
				reqArgs.addAll(getNoCmdReqArgs(subCode, getCommon));
			}
		}
		return reqArgs;
	}

	// 获取非@Cmd标记的方法reqName, cmd(仅有方法名)
	private List<String[]> getNoCmdReqArgs(String code, int getCommon){
		List<String[]> reqArgs = new ArrayList<>();
		if(StringUtils.isBlank(code) || getCommon==0){
			return reqArgs;
		}
		String[] lines = code.split("[\r\n]+");
		String reqName="", cmd="";
		for (int i = 0; i < lines.length; i++) {
			String line = lines[i];
			if(StringUtils.isBlank(line)){
				continue;
			}if(StringAnalysisUtil.notMethodSignature(line)){
				// 简单处理注释信息。
				reqName += StringAnalysisUtil.getComment(line);
			}else{
				// 完整的方法签名
				if (!line.contains(")")) {
					for (int j = 1; j < lines.length-i; j++) {
						line += lines[++i];
						if (line.contains(")")) {
							break;
						}
					}
				}
				String[] methodInfo = StringAnalysisUtil.getMethodInfo(line);
				if(methodInfo==null){
					continue;
				}
				cmd = methodInfo[1];
				reqArgs.add(new String[]{reqName, cmd+" IN"});
				reqName = "";
			}

		}
		return reqArgs;

	}

	private void printOneService(String path) {
		String code = "";
		String cmdPrefix = "cmdPrefix";
		// 获取cmd前缀、content
		List<String> classInfo = StringAnalysisUtil.getClassInfo(path, true);
		cmdPrefix = classInfo.get(0)+"."+classInfo.get(1);
		code = classInfo.get(2);

		List<String[]> reqArgs = getReqArgs(code, cmdPrefix, 1);
		if (reqArgs == null) return;

		String serviceName = cmdPrefix.substring(Math.max(cmdPrefix.lastIndexOf(".")+1, 0));
		if(reqArgs.size()>0){
			System.out.println(serviceName);
			reqArgs.stream()
					.forEach(strs->{
						// 只打印方法名
						System.out.println(String.format("\t%s，%s",
								strs[1].substring(Math.max(strs[1].lastIndexOf(".")+1, 0)),
								strs[0])
						);
					});
		}

	}


	// 1文件名，2请求
	public static final String POSTMAN_COLLECTION_TEMPLATE = "{\n" +
			"\t\"info\": {\n" +
			"\t\t\"name\": \"%1$s\",\n" +
			"\t\t\"schema\": \"https://schema.getpostman.com/json/collection/v2.1.0/collection.json\"\n" +
			"\t},\n" +
			"\t\"item\": [{\"name\":\"a\", \"item\":[%2$s]}\n" +
			"\t]" +
			"}";


	public interface ReqGenerator {
		String TEST_SCRIPT = "tests['ok']=pm.response.json().errCode==0";

		default String getReq(Object... args) {
			return String.format(getItemTemplate(), args);
		}

		String getItemTemplate();
	}

	// 包含group、cmd等信息
	class XssdReqGenerator implements ReqGenerator {

		@Override
		public String getItemTemplate() {
			// 参数顺序：reqName, GROUP_NAME, cmd, TOKEN_NAME, TEST_SCRIPT, HOST_NAME
			return "{\n"
					+ "  \"name\": \"%1$s\",\n"
					+ "  \"event\": [\n"
					+ "    {\n"
					+ "      \"listen\": \"test\",\n"
					+ "      \"script\": {\n"
					+ "        \"exec\": [\n"
					+ "          \"%5$s\"\n"
					+ "        ],\n"
					+ "        \"type\": \"text/javascript\"\n"
					+ "      }\n"
					+ "    }\n"
					+ "  ],\n"
					+ "  \"request\": {\n"
					+ "    \"method\": \"POST\",\n"
					+ "    \"header\": [\n"
					+ "      {\n"
					+ "        \"value\": \"application/json\",\n"
					+ "        \"key\": \"Content-Type\"\n"
					+ "      },\n"
					+ "      {\n"
					+ "        \"value\": \"{{%4$s}}\",\n"
					+ "        \"key\": \"token\"\n"
					+ "      }\n"
					+ "    ],\n"
					+ "    \"body\": {\n"
					+ "      \"mode\": \"raw\",\n"
					+ "      \"raw\": \"{\\r\\n  \\\"id\\\": 1,\\r\\n  \\\"a\\\": \\\"1\\\"\\r\\n}\"\n"
					+ "    },\n"
					+ "    \"url\": {\n"
					+ "      \"raw\": \"{{%6$s}}/api/?group=%2$s&cmd=%3$s\",\n"
					+ "      \"host\": [\n"
					+ "        \"{{%6$s}}\"\n"
					+ "      ],\n"
					+ "      \"path\": [\n"
					+ "        \"api\",\n"
					+ "        \"\"\n"
					+ "      ],\n"
					+ "      \"query\": [\n"
					+ "        {\n"
					+ "          \"key\": \"group\",\n"
					+ "          \"value\": \"%2$s\"\n"
					+ "        },\n"
					+ "        {\n"
					+ "          \"key\": \"cmd\",\n"
					+ "          \"value\": \"%3$s\"\n"
					+ "        }\n"
					+ "      ]\n"
					+ "    }\n"
					+ "  }\n"
					+ "}";
		}
	}

	public static class CommonReqGenerator implements ReqGenerator {

		@Override
		public String getItemTemplate() {
      // 参数顺序：reqName, reqPath、COOKIE_NAME、TOKEN_NAME, TEST_SCRIPT, HOST_NAME
      // 项目公用path包含在HOST_NAME
      return "{\n"
          + "  \"name\": \"%1$s\",\n"
          + "  \"event\": [\n"
          + "    {\n"
          + "      \"listen\": \"test\",\n"
          + "      \"script\": {\n"
          + "        \"exec\": [\n"
          + "          \"%5$s\"\n"
          + "        ],\n"
          + "        \"type\": \"text/javascript\"\n"
          + "      }\n"
          + "    }\n"
          + "  ],\n"
          + "  \"request\": {\n"
          + "    \"method\": \"%7$s\",\n"
          + "    \"header\": [\n"
          + "      {\n"
          + "        \"value\": \"application/json\",\n"
          + "        \"key\": \"Content-Type\"\n"
          + "      },\n"
          + "      {\n"
          + "        \"value\": \"{{%3$s}}\",\n"
          + "        \"key\": \"cookie\"\n"
          + "      },\n"
          + "      {\n"
          + "        \"value\": \"{{%4$s}}\",\n"
          + "        \"key\": \"token\"\n"
          + "      }\n"
          + "    ],\n"
          + "    \"body\": {\n"
          + "      \"mode\": \"raw\",\n"
          + "      \"raw\": \"{\\r\\n  \\\"id\\\": 1,\\r\\n  \\\"a\\\": \\\"1\\\"\\r\\n}\"\n"
          + "    },\n"
          + "    \"url\": {\n"
          + "      \"raw\": \"{{%6$s}}/%2$s\",\n"
          + "      \"host\": [\n"
          + "        \"{{%6$s}}\"\n"
          + "      ],\n"
          + "    \"path\": [\n"
          + "      \"%2$s\"\n"
          + "      ]"
          + "    }\n"
          + "  }\n"
          + "}";
		}
	}

}
